#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "../ddxc.h"
#include <sqlite3.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>

#define NAME_SIZE 64
#define PASSWORD_SIZE 64
#define SEARCH 64
#define NO -1
#define MEMBER_LISTNAME "member"
#define DICTIONALY_LISTNAME "dic"

#define ENROLL_RT 666
#define WRONGNAME -2

#define EXIST 1

typedef struct resources{//存放sock与数据库指针
    int sockfd;
    sqlite3 *db;
}resourcesnode,*resourceslist;


typedef struct member{//账户
    char name[NAME_SIZE];
    char password[PASSWORD_SIZE];
}membernode,*memberlist;

static pthread_mutex_t lock;//线程锁

/*
    指针检查
*/
int pointer_check(int num,void* value1,void* value2,void* value3,void* value4,void* value5,void* value6){
    if(num >=1){
        if(value1 == NULL){
            return -1;
        }
    }
    if(num >=2){
        if(value2 == NULL){
            return -1;
        }
    }
    if(num >=3){
        if(value3 == NULL){
            return -1;
        }
    }
    if(num >=4){
        if(value4 == NULL){
            return -1;
        }
    }
    if(num >=5){
        if(value5 == NULL){
            return -1;
        }
    }
    if(num >=6){
        if(value6 == NULL){
            return -1;
        }
    }
    return 0;
}

/*
    传入字符串指针time_str，将当前时间写入进time_str
*/
int now_time(char* time_str){
    if(pointer_check(1,time_str,NULL,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }

    time_t timep;
    struct tm *p;


    time(&timep); // 获取当前时间的秒数
    p = gmtime(&timep); // 将秒数转换为 tm 结构体

    // 将时间信息格式化为字符串
    sprintf(time_str, "%d年%d月%d日 %d:%d:%d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec);
    // printf("当前时间为：%s\n",time_str);


    return 0;
}


/*
    listname:要插入的目标表名  value1:第一栏的值   value2:第二栏的值 
    将值插入表中
*/
int do_insert(sqlite3 *db,char* listname,char* value1,char* value2) {
    if(pointer_check(4,listname,value1,value2,db,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    const char ch[128]="";
    sprintf((char *)ch,"insert into %s values('%s','%s')",listname,value1,value2);

    char *zErrMsg = NULL;
    
    if (sqlite3_exec(db, ch, NULL,NULL, &zErrMsg) != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
        return -1;
    }
    return 0;
}

int history_add(sqlite3 *db,memberlist member,int prow,char* name){
    if(pointer_check(2,db,member,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    if(prow > 0 && name != NULL){//如果查询的数据存在，且目标为单词表
        char listname[64]="";
        char time[64]="";
        sprintf(listname,"%s_history",member->name);

        now_time(time);//获取时间
        do_insert(db,listname,name,time);//将查询记录添加进历史记录
    }

    return 0;
}
 
int do_show_sample(int sockfd,sqlite3 *db,const char* sql,memberlist member,char* name) {
    if(pointer_check(3,db,(char*)sql,member,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    char *zErrMsg = NULL;
    int prow=0,pcloum=0;
    char **result=NULL;
    
    if (sqlite3_get_table(db,sql,&result,&prow,&pcloum,&zErrMsg) != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
        return -1;
    }else{
        if(sticky_packs_send_func(sockfd,&prow,INT_TYPE,prow) == -1){
            printf("err");
            return -1;
        }
        if(sticky_packs_send_func(sockfd,&pcloum,INT_TYPE,pcloum) == -1){
            printf("err");
            return -1;
        }
        // printf("prow = %d\n",prow);
        if(prow > 0 && pcloum > 0){
            history_add(db,member,prow,name);
            int num=pcloum;
            char* buf=(char*)malloc(BUF_SIZE);
            if(buf == NULL){
                perror("malloc err");
                return -1;
            }
            memset(buf,0,BUF_SIZE);
            for(int i=0;i<prow;i++){
                for(int j=0;j<pcloum;j++){
                    printf("%s = %s\n",result[j],result[num]);
                    strcpy((buf+INT_SIZE),result[j]);

                    if(sticky_packs_send_func(sockfd,buf,STRING_TYPE,(strlen((buf + INT_SIZE))+1)) == -1){
                        printf("err");
                        free(buf);
                        buf=NULL;
                        return -1;
                    }
                    
                    strcpy((buf + INT_SIZE),result[num]);

                    if(sticky_packs_send_func(sockfd,buf,STRING_TYPE,(strlen((buf + INT_SIZE))+1)) == -1){
                        printf("err");
                        free(buf);
                        buf=NULL;
                        return -1;
                    }
                    num++;
                }
                printf("\n");
            }
            free(buf);
            buf=NULL;
            return prow;
        }else{
            return prow;
        }
    }
    sqlite3_free_table(result);
    
    return prow;
}

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
    if(pointer_check(2,argv,azColName,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    int i=0;
    if(NotUsed != NULL){
        *((int*)NotUsed)=argc;
    }
    // printf("argc =%d\n",argc);
    for (i = 0; i < argc; i++)
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}

int do_search(sqlite3 *db,char* listname,char* tag,char* name,memberlist member) {
    if(pointer_check(6,db,listname,tag,name,member,time) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    const char ch[128]="";
    sprintf((char *)ch,"select * from %s where %s='%s'",listname,tag,name);
    // printf("%s\n",ch);
    char *zErrMsg = NULL;
    int ret=-1,temp=0;
    ret=sqlite3_exec(db,ch,callback,&temp, &zErrMsg);//搜索

    if (ret != SQLITE_OK){
        temp =-1;   
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }
    
    return temp;
}


/*  member_insert
    将账户添加到帐号表中，如果账户存在，则会返回1,search模式下，将不会创建搜索历史表

*/
int member_insert(sqlite3 *db,memberlist member,int type){//将账户添加到帐号表中，如果账户存在，则会返回1,search模式下，将不会创建搜索历史表
    if(pointer_check(2,db,member,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    char *zErrMsg = NULL;

    if(do_search(db,MEMBER_LISTNAME,"name",member->name,member) > 0){
        // printf("存在\n");
        return 1;
    }else if(type != SEARCH){
        do_insert(db,MEMBER_LISTNAME,member->name,member->password);
        const char ch[128]="";
        sprintf((char *)ch,"create table %s_history(word text,time text)",member->name);
        if (sqlite3_exec(db,ch,NULL,NULL, &zErrMsg) != SQLITE_OK){
            fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
            
        }
    }
    
    return 0;
}

int dic_search(int sockfd,sqlite3 *db,memberlist member,const char *sql,char* name){
    if(pointer_check(3,db,(char*)sql,member,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    int temp=do_show_sample(sockfd,db,sql,member,name);
    if(temp == 0){
        printf("不存在\n");
    }
    
}

int home_page(int sockfd,sqlite3 *db,memberlist member){
    if(pointer_check(2,db,member,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    char clean[64]="";
    int n=-1;
    while ( 1 ) {
        if(sticky_packs_recv_func(sockfd,&n,INT_TYPE) == -1){
            return -1;
        }
        switch ( n ) {
            case 1 : //单词查询
                {   //pthread_mutex_lock(&lock);
                    const char sql[128]="";
                    char name[64]="";
                    if(sticky_packs_recv_func(sockfd,name,STRING_TYPE) == -1){
                        return -1;
                    }
                    printf("查询 = %s\n",name);
                    sprintf((char *)sql,"select * from dic where word='%s'",name);

                    dic_search(sockfd,db,member,sql,name);
                    //pthread_mutex_unlock(&lock);
                }
                break; 
            case 2 ://历史记录查询
                {   //pthread_mutex_lock(&lock);
                    char name[64]="";
                    const char sql[128]="";

                    sprintf(name,"%s_history",member->name);
                    printf("%s\n",name);
        
                    sprintf((char *)sql,"select * from %s",name);
                    dic_search(sockfd,db,member,sql,NULL);
                    //pthread_mutex_unlock(&lock);
                } 
                break; 
            case 3 : //退出
                return 0;
                break; 
            default: 
                printf("err option\n"); 
            break; 
        } 
    }
}

int denglu(int sockfd,sqlite3 *db,memberlist member,int type){
    if(pointer_check(2,db,member,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    int temp=-1;
    if(sticky_packs_recv_func(sockfd,&temp,INT_TYPE) == -1){//接受客户端信号，输入表名是否正确
        return -1;
    }
    if(temp == WRONGNAME){//不正确就直接退出
        return temp;
    }
    if(sticky_packs_recv_func(sockfd,member->name,STRING_TYPE) == -1){
        return -1;
    }
    if(sticky_packs_recv_func(sockfd,member->password,STRING_TYPE) == -1){
        return -1;
    }
    temp=member_insert(db,member,type);//如果账户存在，则进入主页(type == SEARCH,为仅查询模式)
    
    if(sticky_packs_send_func(sockfd,&temp,INT_TYPE,temp) == -1){
        printf("err");
        return -1;
    }
    
    return temp;
}

int login(int sockfd,sqlite3 *db,memberlist member){
    if(pointer_check(2,db,member,NULL,NULL,NULL,NULL) == -1 ){
        printf("pointer_chek err\n");
        return -1;
    }
    char clean[64]="";
    int n=-1;
    strcpy(clean+INT_SIZE,"wellcome to hy云词典");
    if(sticky_packs_send_func(sockfd,clean,STRING_TYPE,(strlen(clean+INT_SIZE)+1)) == -1){
        printf("err");
        return -1;
    }
    printf("%s\n",clean+INT_SIZE);
    while ( 1 ) {
         
        if(sticky_packs_recv_func(sockfd,&n,INT_TYPE) == -1){
            return -1;
        }
        switch ( n ) {
            case 1 : //登陆
                // pthread_mutex_lock(&lock);
                if(denglu(sockfd,db,member,SEARCH)  == 1){
                    // pthread_mutex_unlock(&lock);
                    if(home_page(sockfd,db,member) < 0){
                        return -1;
                    }else{
                        break;
                    }
                }
                // pthread_mutex_unlock(&lock);
                break; 
            case 2 : //注册
                pthread_mutex_lock(&lock);
                if(denglu(sockfd,db,member,NO) < 0){
                    break;
                }
                pthread_mutex_unlock(&lock);
                break; 
            case 3 : 
                return 0; 
            default: 
                printf("err option\n"); 
            break; 
        } 
    }
}

int sever_creat(int* sockfd){
    if(sockfd == NULL){
        return -1;
    }
    *sockfd = socket(AF_INET,SOCK_STREAM,0);//ipv4,tcp
    if(*sockfd == -1){
        perror("sock err");
        return -1;
    }
    //服务器地址:IP 端口号
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port =htons(8888);
    
    addr.sin_addr.s_addr=INADDR_ANY;//本地的ip都可以
    printf("IP=%s\n",inet_ntoa(addr.sin_addr));
    socklen_t addrlen= sizeof(addr);
    //绑定
    if(bind(*sockfd,(struct sockaddr*)&addr,addrlen) == -1){
        perror("bind err");
        close(*sockfd);
        return -1;
    }

    //监听
    if(listen(*sockfd,5) == -1){
        perror("listen err");
        close(*sockfd);
        return -1;
    }
    printf("waiting client connect!\n");

    //响应连接
    // struct sockaddr_in client_addr;
    // socklen_t clientlen;
    // *clientfd=accept(*sockfd,NULL,NULL);
    // if(*clientfd < 0){
    //     perror("accept err");
    //     close(*sockfd);
    //     return -1;
    // }
    // printf("new connect comming\n");

    return 0;
}

void* handler_thread(void* arg){
    if(arg == NULL){
        pthread_exit(NULL);
    }
    resourceslist src=(resourceslist)arg;
    membernode node;
    login(src->sockfd,src->db,&node);
    free(arg);
    arg=NULL;
    src=NULL;
    close(src->sockfd);
    pthread_exit(NULL);
}

int main(void){
    int sockfd=-1,clientfd =-1;
    if(sever_creat(&sockfd) < 0){
        return -1;
    }

    //数据库初始化
    sqlite3 *db; 
    int n=-1;  
    char *zErrMsg = NULL;
    if (sqlite3_open("my.db", &db) < 0) { 
        printf("fail to sqlite3_open : %s\n", sqlite3_errmsg(db)); 
        return -1; 
    }
    if (sqlite3_exec(db, "create table dic(word text,parse text)",NULL,NULL, &zErrMsg) != SQLITE_OK){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }
    if (sqlite3_exec(db, "create table member(name text,password text)",NULL,NULL, &zErrMsg) != SQLITE_OK){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }
    

    // struct sockaddr_in cliaddr;
 

    pthread_t tid=-1;
    int i=0;
    
    if(pthread_mutex_init(&lock,NULL) != 0){//申请线程锁
        perror("pthread_mutex_init err");
        return -1;
    }

    //多线程
    while (1)//
    {   
        clientfd = accept(sockfd,NULL,NULL);
        if (clientfd < 0)
        {
            perror("accept err");
            continue;
        }else{
            resourceslist new_sock=(resourceslist)malloc(sizeof(resourcesnode));
            if(new_sock == NULL){
                perror("malloc err");
                close(clientfd);
                continue;
            }
            new_sock->sockfd=clientfd;
            new_sock->db=db;
            if(pthread_create(&tid,NULL,handler_thread,(void*)new_sock) != 0){
                perror("pthread_create err");
 
                close(clientfd);
                continue;
            }
            if(pthread_detach(tid) != 0){
                perror("pthread_detach err");
                free(new_sock);
                close(clientfd);
                pthread_cancel(tid);//终止线程
                pthread_join(tid,NULL);//回收资源
                continue;
            }

        }
        i++;
        printf("第%d个\n",i);
    }


    //关闭
    close(sockfd);
    close(clientfd);
    sqlite3_close(db);


    return 0;
}
